package nes

import (
	"fmt"
	"os"

	"github.com/imacks/bitflags-go"
)

const (
	CPU_FLAGS_CARRY             byte = 0b0000_0001
	CPU_FLAGS_ZERO              byte = 0b0000_0010
	CPU_FLAGS_INTERRUPT_DISABLE byte = 0b0000_0100
	CPU_FLAGS_DECIMAL_MODE      byte = 0b0000_1000
	CPU_FLAGS_BREAK             byte = 0b0001_0000
	CPU_FLAGS_BREAK2            byte = 0b0010_0000
	CPU_FLAGS_OVERFLOW          byte = 0b0100_0000
	CPU_FLAGS_NEGATIV           byte = 0b1000_0000
)

const (
	Immediate uint8 = iota
	ZeroPage
	ZeroPage_X
	ZeroPage_Y
	Absolute
	Absolute_X
	Absolute_Y
	Indirect_X
	Indirect_Y
	NoneAddressing
)

const (
	STACK       = 0x0100
	STACK_RESET = 0xfd
)

type InterruptType int

const (
	NMI InterruptType = iota
)

type Interrupt struct {
	IType      InterruptType
	VectorAddr uint16
	BFlagMask  uint8
	CPUCycles  uint8
}

var NMIInterrupt = Interrupt{
	IType:      NMI,
	VectorAddr: 0xfffa,
	BFlagMask:  0b00100000,
	CPUCycles:  2,
}

type Mem struct {
	Bus *Bus
}

func (c *Mem) Mem_read(address uint16) byte {
	return c.Bus.MemRead(address)
}

func (c *Mem) Mem_write(address uint16, value byte) {
	c.Bus.MemWrite(address, value)
}

func (c *Mem) Mem_read_u16(address uint16) uint16 {
	lo := c.Mem_read(address)
	hi := c.Mem_read(address + 1)
	return uint16(hi)<<8 | uint16(lo)
}

func (c *Mem) Mem_write_u16(address uint16, value uint16) {
	lo := byte(value & 0xff)
	hi := byte(value >> 8)
	c.Mem_write(address, lo)
	c.Mem_write(address+1, hi)
}

type CPU struct {
	Register_a     byte
	Register_x     byte
	Register_y     byte
	Status         byte
	StackPointer   byte
	ProgramCounter uint16
	Mem
}

func NewCpu(bus *Bus) CPU {
	cpu := CPU{
		Register_a:     0,
		Register_x:     0,
		Register_y:     0,
		Status:         bitflags.Set(CPU_FLAGS_INTERRUPT_DISABLE, CPU_FLAGS_BREAK2),
		ProgramCounter: 0,
		StackPointer:   STACK_RESET,
	}

	cpu.Bus = bus

	return cpu
}

func pageCross(addr1 uint16, addr2 uint16) bool {
	return addr1&0xff00 != addr2&0xff00
}

func (c *CPU) get_absolute_address(mode uint8, addr uint16) (uint16, bool) {
	switch mode {
	case ZeroPage:
		return uint16(c.Mem_read(addr)), false
	case Absolute:
		return c.Mem_read_u16(addr), false
	case ZeroPage_X:
		return uint16(c.Mem_read(addr) + c.Register_x), false
	case ZeroPage_Y:
		return uint16(c.Mem_read(addr) + c.Register_y), false
	case Absolute_X:
		base := c.Mem_read_u16(addr)
		addr := base + uint16(c.Register_x)
		return addr, pageCross(base, addr)
	case Absolute_Y:
		base := c.Mem_read_u16(addr)
		addr := base + uint16(c.Register_y)
		return addr, pageCross(base, addr)
	case Indirect_X:
		base := c.Mem_read(addr)
		ptr := uint8(base) + c.Register_x
		lo := c.Mem_read(uint16(ptr))
		hi := c.Mem_read(uint16(ptr + 1))
		return uint16(hi)<<8 | uint16(lo), false
	case Indirect_Y:
		base := c.Mem_read(addr)
		lo := c.Mem_read(uint16(base))
		hi := c.Mem_read(uint16(base + 1))
		ptr := uint16(hi)<<8 | uint16(lo)
		addr := ptr + uint16(c.Register_y)
		return addr, pageCross(addr, ptr)
	case NoneAddressing:
		return 0, false
	default:
		panic("unhandled default case")
	}
}

func (c *CPU) get_operand_address(mode uint8) (uint16, bool) {
	switch mode {
	case Immediate:
		return c.ProgramCounter, false
	default:
		return c.get_absolute_address(mode, c.ProgramCounter)
	}
}

func (c *CPU) ldy(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	c.Register_y = data
	c.updateZeroAndNegativeFlags(c.Register_y)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) ldx(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	c.Register_x = data
	c.updateZeroAndNegativeFlags(c.Register_x)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) lda(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	c.set_register_a(data)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) sta(mode uint8) {
	addr, _ := c.get_operand_address(mode)
	c.Mem_write(addr, c.Register_a)
}

func (c *CPU) set_register_a(value byte) {
	c.Register_a = value
	c.updateZeroAndNegativeFlags(c.Register_a)
}

func (c *CPU) and(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	c.set_register_a(c.Register_a & data)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) eor(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	c.set_register_a(c.Register_a ^ data)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) ora(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	c.set_register_a(c.Register_a | data)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) tax() {
	c.Register_x = c.Register_a
	// fmt.Println(c.Register_a, "c.Register_a")
	c.updateZeroAndNegativeFlags(c.Register_x)
}

func (c *CPU) updateZeroAndNegativeFlags(result byte) {
	if result == 0 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_ZERO)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_ZERO)
	}

	if result>>7 == 1 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_NEGATIV)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_NEGATIV)
	}
}

func (c *CPU) inx() {
	c.Register_x++
	c.updateZeroAndNegativeFlags(c.Register_x)
}

func (c *CPU) iny() {
	c.Register_y++
	c.updateZeroAndNegativeFlags(c.Register_y)
}

func (c *CPU) setCarryFlag() {
	c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
}

func (c *CPU) clearCarryFlag() {
	c.Status = bitflags.Del(c.Status, CPU_FLAGS_CARRY)
}

func (c *CPU) Reset() {
	c.Register_a = 0
	c.Register_x = 0
	c.Register_y = 0
	c.StackPointer = STACK_RESET
	c.Status = bitflags.Set(CPU_FLAGS_INTERRUPT_DISABLE, CPU_FLAGS_BREAK2)
	c.ProgramCounter = c.Mem_read_u16(0xFFFC)



}

func (c *CPU) Dump() string {
	return fmt.Sprintf("A: %02x X: %02x Y: %02x SP: %02x PC: %02x Status:%02x \n", c.Register_a, c.Register_x, c.Register_y, c.StackPointer, c.ProgramCounter, c.Status)
}

func (c *CPU) load_and_run(program []byte) {
	c.Load(program)
	c.Reset()
	c.ProgramCounter = 0x0600
	c.run()
}

func (c *CPU) Load(program []byte) {

	for i, b := range program {
		c.Mem_write(uint16(i)+0x0600, b)
	}

}

func (c *CPU) add_to_register_a(data uint8) {
	cpu_carry := 1
	if bitflags.Has(c.Status, CPU_FLAGS_CARRY) {
		cpu_carry = 1
	} else {
		cpu_carry = 0
	}

	sum := uint16(c.Register_a) + uint16(data) + uint16(cpu_carry)
	carry := sum > 0xFF

	if carry {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_CARRY)
	}

	result := byte(sum)

	if (data^result)&(result^c.Register_a)&0x80 != 0 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_OVERFLOW)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_OVERFLOW)
	}

	c.set_register_a(result)
}

func (c *CPU) sub_from_register_a(data uint8) {
	c.add_to_register_a(byte(int8(-data) - 1))
}

func (c *CPU) and_with_register_a(data uint8) {
	c.set_register_a(c.Register_a & data)
}

func (c *CPU) xor_with_register_a(data uint8) {
	c.set_register_a(c.Register_a ^ data)
}

func (c *CPU) or_with_register_a(data uint8) {
	c.set_register_a(c.Register_a | data)
}

func (c *CPU) run() {
	c.Run_with_callback(func(c *CPU) {})
}

func (c *CPU) sbc(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	c.add_to_register_a(byte(int8(-data) - 1))
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) adc(mode uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	c.add_to_register_a(data)
	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) stack_pop() byte {
	c.StackPointer++
	return c.Mem_read(uint16(uint16(STACK) + uint16(c.StackPointer)))
}

func (c *CPU) stack_push(value byte) {
	c.Mem_write(uint16(uint16(STACK)+uint16(c.StackPointer)), value)
	c.StackPointer--
}

func (c *CPU) stack_push_u16(value uint16) {
	lo := byte(value & 0xff)
	hi := byte(value >> 8)
	c.stack_push(hi)
	c.stack_push(lo)
}

func (c *CPU) stack_pop_u16() uint16 {
	lo := c.stack_pop()
	hi := c.stack_pop()
	return uint16(hi)<<8 | uint16(lo)
}

func (c *CPU) asl_accumulator() {
	data := c.Register_a
	if data>>7 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data << 1
	c.set_register_a(data)
}

func (c *CPU) asl(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	if data>>7 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data << 1
	c.Mem_write(addr, data)
	c.updateZeroAndNegativeFlags(data)
	return data
}

func (c *CPU) lsr_accumulator() {
	data := c.Register_a
	if data&1 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data >> 1
	c.set_register_a(data)
}

func (c *CPU) lsr(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	if data&1 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data >> 1
	c.Mem_write(addr, data)
	c.updateZeroAndNegativeFlags(data)
	return data
}

func (c *CPU) rol_accumulator() {
	data := c.Register_a
	oldCarry := bitflags.Has(c.Status, CPU_FLAGS_CARRY)

	if data>>7 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data << 1
	if oldCarry {
		data = data | 1
	}

	c.set_register_a(data)
}

func (c *CPU) rol(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	oldCarry := bitflags.Has(c.Status, CPU_FLAGS_CARRY)

	if data>>7 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data << 1
	if oldCarry {
		data = data | 1
	}

	c.Mem_write(addr, data)
	c.update_negative_flags(data)
	return data
}

func (c *CPU) ror_accumulator() {
	data := c.Register_a
	oldCarry := bitflags.Has(c.Status, CPU_FLAGS_CARRY)

	if data&1 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data >> 1
	if oldCarry {
		data = data | 0b10000000
	}

	c.set_register_a(data)
}

func (c *CPU) update_negative_flags(data byte) {
	if data>>7 == 1 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_NEGATIV)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_NEGATIV)
	}
}

func (c *CPU) ror(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	oldCarry := bitflags.Has(c.Status, CPU_FLAGS_CARRY)

	if data&1 == 1 {
		c.setCarryFlag()
	} else {
		c.clearCarryFlag()
	}

	data = data >> 1
	if oldCarry {
		data = data | 0b10000000
	}

	c.Mem_write(addr, data)
	c.update_negative_flags(data)
	return data

}

func (c *CPU) inc(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	data++
	c.Mem_write(addr, data)
	c.updateZeroAndNegativeFlags(data)
	return data
}

func (c *CPU) dey() {
	c.Register_y--
	c.updateZeroAndNegativeFlags(c.Register_y)
}

func (c *CPU) dex() {
	c.Register_x--
	c.updateZeroAndNegativeFlags(c.Register_x)
}

func (c *CPU) dec(mode uint8) uint8 {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)
	data--
	c.Mem_write(addr, data)
	c.updateZeroAndNegativeFlags(data)
	return data
}

func (c *CPU) pla() {
	c.Register_a = c.stack_pop()
	c.updateZeroAndNegativeFlags(c.Register_a)
}

func (c *CPU) plp() {
	c.Status = c.stack_pop()
	c.Status = bitflags.Del(c.Status, CPU_FLAGS_BREAK)
	c.Status = bitflags.Set(c.Status, CPU_FLAGS_BREAK2)
}

func (c *CPU) php() {
	flags := c.Status
	flags = bitflags.Set(flags, CPU_FLAGS_BREAK)
	flags = bitflags.Set(flags, CPU_FLAGS_BREAK2)
	c.stack_push(flags)
}

func (c *CPU) bit(mode uint8) {
	addr, _ := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	if data&c.Register_a == 0 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_ZERO)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_ZERO)
	}

	// 可能出问题
	if data&0b10000000 > 0 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_NEGATIV)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_NEGATIV)
	}

	if data&0b01000000 > 0 {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_OVERFLOW)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_OVERFLOW)
	}
}

func (c *CPU) compare(mode uint8, compare_with uint8) {
	addr, cross := c.get_operand_address(mode)
	data := c.Mem_read(addr)

	if data <= compare_with {
		c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
	} else {
		c.Status = bitflags.Del(c.Status, CPU_FLAGS_CARRY)
	}

	compare_with = compare_with - data

	c.updateZeroAndNegativeFlags(compare_with)

	if cross {
		c.Bus.Tick(1)
	}
}

func (c *CPU) branch(condition bool) {
	if condition {
		offset := int8(c.Mem_read(c.ProgramCounter))
		c.ProgramCounter = c.ProgramCounter + 1 + uint16(offset)
	}
}

// interrupt handling
func (c *CPU) interrupt(interrupt Interrupt) {
	c.stack_push_u16(c.ProgramCounter)
	flag := c.Status
	if interrupt.BFlagMask&0b010000 == 1 {
		flag = bitflags.Set(flag, CPU_FLAGS_BREAK)
	} else {
		flag = bitflags.Del(flag, CPU_FLAGS_BREAK)
	}

	if interrupt.BFlagMask&0b100000 == 1 {
		flag = bitflags.Set(flag, CPU_FLAGS_BREAK2)
	} else {
		flag = bitflags.Del(flag, CPU_FLAGS_BREAK2)
	}

	c.stack_push(flag)
	c.Status = bitflags.Set(c.Status, CPU_FLAGS_INTERRUPT_DISABLE)
	c.Bus.Tick(interrupt.CPUCycles)
	c.ProgramCounter = c.Mem_read_u16(interrupt.VectorAddr)
}

func (c *CPU) Run_with_callback(callback func(*CPU)) {
// 创建日志文件
	 f, _ := os.Create("log.txt")
	 i := 0

	for {
		pollNmiStatus := c.Bus.PollNmiStatus()

		f.WriteString(c.Dump())
		i++
		if i > 7840 {
			os.Exit(1)
		}
	

		if pollNmiStatus != 255 {
			fmt.Println("NMI", pollNmiStatus)
			c.interrupt(NMIInterrupt)
		}

		code := c.Mem_read(c.ProgramCounter)
		c.ProgramCounter++
		program_counter_state := c.ProgramCounter

		opcode := CPU_OPS_CODES_MAP[code]

	

		switch code {

		case 0xa9, 0xa5, 0xb5, 0xad, 0xbd, 0xb9, 0xa1, 0xb1:
			{
				c.lda(opcode.Mode)
			}
		case 0xAA:
			{
				c.tax()
			}

		case 0xe8:
			{
				c.inx()
			}
		case 0x00:
			{
				return
			}
		case 0xd8:
			{
				c.Status = bitflags.Del(c.Status, CPU_FLAGS_DECIMAL_MODE)
			}
		case 0x58:
			{
				c.Status = bitflags.Del(c.Status, CPU_FLAGS_INTERRUPT_DISABLE)
			}
		case 0xb8:
			{
				c.Status = bitflags.Del(c.Status, CPU_FLAGS_OVERFLOW)
			}
		case 0x18:
			{
				c.clearCarryFlag()
			}
		case 0x38:
			{
				c.setCarryFlag()
			}
		case 0x78:
			{
				c.Status = bitflags.Set(c.Status, CPU_FLAGS_INTERRUPT_DISABLE)
			}
		case 0xf8:
			{
				c.Status = bitflags.Set(c.Status, CPU_FLAGS_DECIMAL_MODE)
			}
		case 0x48:
			{
				c.stack_push(c.Register_a)
			}

		case 0x68:
			{
				c.pla()
			}
		case 0x08:
			{
				c.php()
			}
		case 0x28:
			{
				c.plp()
			}

		case 0x69, 0x65, 0x75, 0x6d, 0x7d, 0x79, 0x61, 0x71:
			{
				c.adc(opcode.Mode)
			}

		case 0xe9, 0xe5, 0xf5, 0xed, 0xfd, 0xf9, 0xe1, 0xf1:
			{
				c.sbc(opcode.Mode)
			}

		case 0x29, 0x25, 0x35, 0x2d, 0x3d, 0x39, 0x21, 0x31:
			{
				c.and(opcode.Mode)
			}

		case 0x49, 0x45, 0x55, 0x4d, 0x5d, 0x59, 0x41, 0x51:
			{
				c.eor(opcode.Mode)
			}
		// ORA
		case 0x09, 0x05, 0x15, 0x0d, 0x1d, 0x19, 0x01, 0x11:
			{
				c.ora(opcode.Mode)
			}
		case 0x4a:
			{
				c.lsr_accumulator()
			}

		case 0x46, 0x56, 0x4e, 0x5e:
			{
				c.lsr(opcode.Mode)
			}

		case 0x0a:
			{
				c.asl_accumulator()
			}

		case 0x06, 0x16, 0x0e, 0x1e:
			{
				c.asl(opcode.Mode)
			}

		case 0x2a:
			{
				c.rol_accumulator()
			}

		case 0x26, 0x36, 0x2e, 0x3e:
			{
				c.rol(opcode.Mode)
			}

		case 0x6a:
			{
				c.ror_accumulator()
			}

		case 0x66, 0x76, 0x6e, 0x7e:
			{
				c.ror(opcode.Mode)
			}

		case 0xe6, 0xf6, 0xee, 0xfe:
			{
				c.inc(opcode.Mode)
			}

		case 0xc8:
			{
				c.iny()
			}

		case 0xc6, 0xd6, 0xce, 0xde:
			{
				c.dec(opcode.Mode)
			}

		case 0xca:
			{
				c.dex()
			}

		case 0x88:
			{
				c.dey()
			}

		case 0xc9, 0xc5, 0xd5, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1:
			{
				c.compare(opcode.Mode, c.Register_a)
			}

		case 0xc0, 0xc4, 0xcc:
			{
				c.compare(opcode.Mode, c.Register_y)
			}

		case 0xe0, 0xe4, 0xec:
			{
				c.compare(opcode.Mode, c.Register_x)
			}

		case 0x4c:
			{
				mem_addr := c.Mem_read_u16(c.ProgramCounter)
				c.ProgramCounter = mem_addr
			}

		case 0x6c:
			{
				var indirect_ref uint16
				mem_addr := c.Mem_read_u16(c.ProgramCounter)

				if mem_addr&0x00FF == 0x00FF {
					lo := c.Mem_read(mem_addr)
					hi := c.Mem_read(mem_addr & 0xFF00)
					indirect_ref = uint16(hi)<<8 | uint16(lo)
				} else {
					indirect_ref = c.Mem_read_u16(mem_addr)
				}

				c.ProgramCounter = indirect_ref
			}

		case 0x20:
			{
				c.stack_push_u16(c.ProgramCounter + 2 - 1)
				target_addr := c.Mem_read_u16(c.ProgramCounter)
				c.ProgramCounter = target_addr
			}

		case 0x60:
			{
				c.ProgramCounter = c.stack_pop_u16() + 1
			}

		case 0x40:
			{
				c.Status = c.stack_pop()
				c.Status = bitflags.Del(c.Status, CPU_FLAGS_BREAK)
				c.Status = bitflags.Set(c.Status, CPU_FLAGS_BREAK2)

				c.ProgramCounter = c.stack_pop_u16()
			}

		case 0xd0:
			{
				c.branch(!bitflags.Has(c.Status, CPU_FLAGS_ZERO))
			}

		case 0x70:
			{
				c.branch(bitflags.Has(c.Status, CPU_FLAGS_OVERFLOW))
			}

		case 0x50:
			{
				c.branch(!bitflags.Has(c.Status, CPU_FLAGS_OVERFLOW))
			}

		// LDX
		case 0xa2, 0xa6, 0xb6, 0xae, 0xbe:
			{
				c.ldx(opcode.Mode)
			}

		//BPL
		case 0x10:
			{
				c.branch(!bitflags.Has(c.Status, CPU_FLAGS_NEGATIV))
			}

		//BMI
		case 0x30:
			{
				c.branch(bitflags.Has(c.Status, CPU_FLAGS_NEGATIV))
			}

		//BEQ
		case 0xf0:
			{
				c.branch(bitflags.Has(c.Status, CPU_FLAGS_ZERO))
			}

		//BCS
		case 0xb0:
			{
				c.branch(bitflags.Has(c.Status, CPU_FLAGS_CARRY))
			}

		//BCC
		case 0x90:
			{
				c.branch(!bitflags.Has(c.Status, CPU_FLAGS_CARRY))
			}

		//BIT
		case 0x24, 0x2c:
			{
				c.bit(opcode.Mode)
			}

		//STA
		case 0x85, 0x95, 0x8d, 0x9d, 0x99, 0x81, 0x91:
			{
				c.sta(opcode.Mode)
			}

		//STX
		case 0x86, 0x96, 0x8e:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				c.Mem_write(addr, c.Register_x)
			}

		//STY
		case 0x84, 0x94, 0x8c:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				c.Mem_write(addr, c.Register_y)
			}

		//LDY
		case 0xa0, 0xa4, 0xb4, 0xac, 0xbc:
			{
				c.ldy(opcode.Mode)
			}

		//NOP
		case 0xea:
			{
			}

		//TAY
		case 0xa8:
			{
				c.Register_y = c.Register_a
				c.updateZeroAndNegativeFlags(c.Register_y)
			}

		//TSX
		case 0xba:
			{
				c.Register_x = c.StackPointer
				c.updateZeroAndNegativeFlags(c.Register_x)
			}

		//TXA
		case 0x8a:
			{
				c.Register_a = c.Register_x
				c.updateZeroAndNegativeFlags(c.Register_a)
			}

		//TXS
		case 0x9a:
			{
				c.StackPointer = c.Register_x
			}

		//TYA
		case 0x98:
			{
				c.Register_a = c.Register_y
				c.updateZeroAndNegativeFlags(c.Register_a)
			}

		// new add

		// DCP
		case 0xc7, 0xd7, 0xcf, 0xdf, 0xdb, 0xc3, 0xd3:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.dec(opcode.Mode)
				data += 1
				c.Mem_write(addr, data)
				if data <= c.Register_a {
					c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
				}

				c.updateZeroAndNegativeFlags(c.Register_a - data)
			}

		// RLA
		case 0x27, 0x37, 0x2f, 0x3f, 0x3b, 0x23, 0x33:
			{
				data := c.rol(opcode.Mode)
				c.and_with_register_a(data)
			}

		// SLO
		case 0x07, 0x17, 0x0f, 0x1f, 0x1b, 0x03, 0x13:
			{
				data := c.asl(opcode.Mode)
				c.or_with_register_a(data)
			}

		// SRE
		case 0x47, 0x57, 0x4f, 0x5f, 0x5b, 0x43, 0x53:
			{
				data := c.lsr(opcode.Mode)
				c.xor_with_register_a(data)
			}

		// SKB
		case 0x80, 0x82, 0x89, 0xc2, 0xe2:
			{

			}

		// AXS
		case 0xcb:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				xAndA := c.Register_x & c.Register_a
				result := xAndA - data

				if data <= xAndA {
					c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
				}

				c.updateZeroAndNegativeFlags(result)
				c.Register_x = result
			}

		// ARR
		case 0x6b:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				c.and_with_register_a(data)
				c.ror_accumulator()
				// TODO: registers
				result := c.Register_a
				bit_5 := (result >> 5) & 1
				bit_6 := (result >> 6) & 1

				if bit_6 == 1 {
					c.Status |= CPU_FLAGS_CARRY
				} else {
					c.Status &^= CPU_FLAGS_CARRY
				}

				if bit_5^bit_6 == 1 {
					c.Status |= CPU_FLAGS_OVERFLOW
				} else {
					c.Status &^= CPU_FLAGS_OVERFLOW
				}

				c.updateZeroAndNegativeFlags(result)
			}

		// SBC
		case 0xeb:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				c.sub_from_register_a(data)
			}

		// ANC
		case 0x0b, 0x2b:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				c.and_with_register_a(data)

				if bitflags.Has(c.Status, CPU_FLAGS_NEGATIV) {
					c.Status = bitflags.Set(c.Status, CPU_FLAGS_CARRY)
				} else {
					c.Status = bitflags.Del(c.Status, CPU_FLAGS_CARRY)
				}
			}

		// ALR
		case 0x4b:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)

				c.and_with_register_a(data)
				c.lsr_accumulator()
			}

		// NOP read
		case 0x04, 0x44, 0x64, 0x14, 0x34, 0x54, 0x74, 0xd4, 0xf4, 0x0c, 0x1c, 0x3c, 0x5c, 0x7c, 0xdc, 0xfc:
			{
				addr, cross := c.get_operand_address(opcode.Mode)
				c.Mem_read(addr)
				if cross {
					c.Bus.Tick(1)
				}
			}

		// RRA
		case 0x67, 0x77, 0x6f, 0x7f, 0x7b, 0x63, 0x73:
			{
				data := c.ror(opcode.Mode)
				c.add_to_register_a(data)
			}

		// ISB
		case 0xe7, 0xf7, 0xef, 0xff, 0xfb, 0xe3, 0xf3:
			{
				data := c.inc(opcode.Mode)
				c.sub_from_register_a(data)
			}

		// NOPS
		case 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x92, 0xb2, 0xd2, 0xf2:
			{

			}

		case 0x1a, 0x3a, 0x5a, 0x7a, 0xda, 0xfa:
			{

			}

		//LAX
		case 0xa7, 0xb7, 0xaf, 0xbf, 0xa3, 0xb3:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				c.set_register_a(data)
				c.Register_x = c.Register_a
			}

		// SAX
		case 0x87, 0x97, 0x8f, 0x83:
			{
				addr, _:= c.get_operand_address(opcode.Mode)
				data := c.Register_a & c.Register_x
				c.Mem_write(addr, data)
			}

		// LXA
		case 0xab:
			{
				c.lda(opcode.Mode)
				c.tax()
			}

		// XAA
		case 0x8b:
			{
				c.Register_a = c.Register_x
				c.updateZeroAndNegativeFlags(c.Register_a)

				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				c.and_with_register_a(data)
			}

		// LAS
		case 0xbb:
			{
				addr, _ := c.get_operand_address(opcode.Mode)
				data := c.Mem_read(addr)
				data &= c.StackPointer
				c.Register_a = data
				c.Register_x = data
				c.StackPointer = data
				c.updateZeroAndNegativeFlags(data)
			}

		// TAS
		case 0x9b:
			{
				data := c.Register_a & c.Register_x
				c.StackPointer = data
				memAddress := c.Mem_read_u16(c.ProgramCounter) + uint16(c.Register_y)

				data = uint8(((memAddress >> 8) + 1)) & uint8(c.StackPointer)
				c.Mem_write(memAddress, byte(data))
			}

		// AHX
		case 0x93:
			{
				pos := c.Mem_read(c.ProgramCounter)
				memAddress := c.Mem_read_u16(uint16(pos)) + uint16(c.Register_y)
				data := c.Register_a & c.Register_x & uint8(memAddress>>8)
				c.Mem_write(memAddress, byte(data))
			}

		// AHX Absolute Y
		case 0x9f:
			{
				memAddress := c.Mem_read_u16(c.ProgramCounter) + uint16(c.Register_y)
				data := c.Register_a & c.Register_x & uint8(memAddress>>8)
				c.Mem_write(memAddress, byte(data))
			}

		// SHX
		case 0x9e:
			{
				memAddress := c.Mem_read_u16(c.ProgramCounter) + uint16(c.Register_y)
				data := c.Register_x & (uint8(memAddress>>8) + 1)
				c.Mem_write(memAddress, byte(data))
			}

		// SHY
		case 0x9c:
			{
				memAddress := c.Mem_read_u16(c.ProgramCounter) + uint16(c.Register_x)
				data := c.Register_y & (uint8(memAddress>>8) + 1)
				c.Mem_write(memAddress, byte(data))
			}

		default:
			{
				fmt.Println("Unknown opcode", opcode)
				return
			}
		}

		if program_counter_state == c.ProgramCounter {
			c.ProgramCounter += uint16(opcode.Len - 1)
		}

		callback(c)
	}
}
